/*!
 * \file Reserva.cpp
 *
 * \date Jul 8, 2014
 * \author correa
 */
#include "Reserva.h"

ReservaInterno::~ReservaInterno()
{
//	set<ReservaNode *>::iterator it;
//	set<ReservaNode *>::iterator tmp;
//	for (it = _proximoTermo.begin(); it != _proximoTermo.end(); ) {
////		tmp = it++;
////		_proximoTermo.erase(tmp);
////		delete (*tmp);
//		if (*it == NULL)
//			cout << "NULL em ~ReservaInterno()?" << endl;
//		++it;
//	}
	while (!_proximoTermo.empty()) {
		set<ReservaNode *>::iterator r = _proximoTermo.begin();
		ReservaNode * node = *r;
		_proximoTermo.erase(r);
		delete node;
	}
}

ReservaClique::ReservaClique(int n) : ReservaInterno(), _n(n), _activa(true), _vertices(n), _desigualdades(),
		_violacionMinima(0), _nprango(0), _nrango(0), _soma(0), _tamano(0), _solucion(), _nclique(0), _nvioladas(0)
{
}

ReservaClique::~ReservaClique()
{
//	set<ReservaNode *>::iterator it;
//	set<ReservaNode *>::iterator tmp;
//	for (it = _proximoTermo.begin(); it != _proximoTermo.end(); ) {
//		tmp = it++;
//		cout << "no erase do Reserva.." << endl;
//		_proximoTermo.erase(tmp);
//		cout << "vai meu filho.." << endl;
//		delete (*tmp);
//		if (*it == NULL)
//			cout << "NULL em ~Reserva()?" << endl;
//		++it;
//	}
	haceInactiva();
}

void ReservaClique::haceInactiva()
{
	_activa = false;
	while (!_proximoTermo.empty()) {
		set<ReservaNode *>::iterator r = _proximoTermo.begin();
		ReservaNode * node = *r;
		_proximoTermo.erase(r);
		delete node;
	}
}

void ReservaClique::haceActiva()
{
	if (_activa)
		haceInactiva();
	_activa = true;
}

bool ReservaClique::esActiva()
{
	return _activa;
}

void ReservaInterno::printRecursivo(VertexSet& v) {
	if (_vertice == -1) {
		for (VertexSetIterator i = v.begin(); i != v.end(); ++i)
			cout << "+ x_" << *i << " ";
		cout << "<= " << 1.0 << endl;
	}
	else {
		set<ReservaNode *>::iterator it;
		for (it = _proximoTermo.begin(); it != _proximoTermo.end(); it++) {
			v.add(_vertice);
			((ReservaInterno *) (*it))->printRecursivo(v);
			v.remove(_vertice);
		}
	}
}

void ReservaClique::print() {
	set<ReservaNode *>::iterator it;
	for (it = _proximoTermo.begin(); it != _proximoTermo.end(); it++) {
		_vertices.removeAll();
		((ReservaInterno *) (*it))->printRecursivo(_vertices);
	}
}

void ReservaClique::agregaClique(const VertexSet& clique) {
	if (!_activa)
		return;

	ReservaInterno * node = this;
	set<ReservaNode *>::iterator it;

	for (VertexSetIterator i = clique.begin(); i != clique.end(); ++i) {
		ReservaNode	termo(*i);
		it = node->_proximoTermo.find(&termo);
		if (it != node->_proximoTermo.end())
			node = (ReservaInterno *) *it;
		else {
			ReservaInterno * nuevo = new ReservaInterno(termo._vertice);
			node->_proximoTermo.insert(nuevo);
			node = nuevo;
		}
	}
	it = node->_proximoTermo.begin();
	if (it == node->_proximoTermo.end() || (*it)->_vertice != -1)
		node->_proximoTermo.insert(new ReservaNode());
}

bool ReservaClique::hayClique() {
	set<ReservaNode *>::iterator it = _proximoTermo.begin();
	return (it != _proximoTermo.end() && (*it)->_vertice != -1);
}

bool ReservaClique::tieneClique(const VertexSet& clique) {
	ReservaInterno * node = this;
	set<ReservaNode *>::iterator it;

	for (VertexSetIterator i = clique.begin(); i != clique.end(); ++i) {
		ReservaNode	termo(*i);
		it = node->_proximoTermo.find(&termo);
		if (it != node->_proximoTermo.end())
			node = (ReservaInterno *) *it;
		else
			return false;
	}
	it = node->_proximoTermo.begin();
	if (it == node->_proximoTermo.end() || (*it)->_vertice != -1)
		return false;
	return true;
}

bool ReservaInterno::buscaCliqueVioladasRecursivo(ReservaClique * r, int nmax) {
	bool ret = false;
	if (_vertice != -1) {
		if ((*r->_solucion)[_vertice] < 1.0-1.0e-5) {
			r->_soma += (*r->_solucion)[_vertice];
			r->_tamano++;
			r->_vertices.add(_vertice);
			set<ReservaNode *>::iterator tmp;
			set<ReservaNode *>::iterator it;
			for (it = _proximoTermo.begin(); ret < nmax && it != _proximoTermo.end(); ) {
				bool b = ((ReservaInterno *) (*it))->buscaCliqueVioladasRecursivo(r, nmax);
				if (b && ((*it)->_vertice == -1 || ((ReservaInterno *) (*it))->_proximoTermo.empty())) {
					tmp = it++;
					delete (*tmp);
					_proximoTermo.erase(tmp);
				}
				else
					++it;
				ret = ret || b;
			}
			r->_vertices.remove(_vertice);
			r->_soma -= (*r->_solucion)[_vertice];
			r->_tamano--;
		}
	}
	else if (r->_soma - 1.0 >= r->_violacionMinima)
	{
		ProjectableCliqueSet * d = new ProjectableCliqueSet(r->_vertices, r->_tamano, r->_soma);
		r->_nclique++;
		r->_desigualdades->push_back(d);
		r->_nvioladas++;
		ret = true;
	}
	else if (++_npruebas >= 3)
		ret = true;

	return ret;
}

int ReservaClique::buscaCliqueVioladas(Solucion& solucion, double violacionMinima, int nmax, list<ProjectableCliqueSet *>& desigualdades) {
	set<ReservaNode *>::iterator it;
	set<ReservaNode *>::iterator tmp;

	_solucion = &solucion;
	_violacionMinima = violacionMinima;
	_desigualdades = &desigualdades;
	_nclique = 0;
	_nrango = 0;
	_nprango = 0;
	_nvioladas = 0;

	for (it = _proximoTermo.begin(); it != _proximoTermo.end() && _nvioladas < nmax;) {
		_vertices.removeAll();
		_soma = 0;
		_tamano = 0;

		bool b = ((ReservaInterno *) (*it))->buscaCliqueVioladasRecursivo(this, nmax);
		if (b && ((*it)->_vertice == -1 || ((ReservaInterno *) (*it))->_proximoTermo.empty())) {
			tmp = it++;
			delete (*tmp);
			_proximoTermo.erase(tmp);
		}
		else
			++it;
	}
	return _nvioladas;
}

int ReservaClique::cliqueVioladas() {
	return _nclique;
}

int ReservaClique::rangoVioladas() {
	return _nrango;
}

int ReservaClique::prangoVioladas() {
	return _nprango;
}
